#include <defs.h>
#include <unistd.h>
#include <stdarg.h>
#include <syscall.h>

#define MAX_ARGS            5

#define NIOS2_READ_R2(r2) \
    do { __asm ("mov %0, r2" : "=r" (r2) ); } while (0)

#define NIOS2_WRITE_R4(value) \
    do { __asm volatile ("mov r4, %z0" : : "rM" (value)); } while (0)
#define NIOS2_WRITE_R5(value) \
    do { __asm volatile ("mov r5, %z0" : : "rM" (value)); } while (0)
#define NIOS2_WRITE_R6(value) \
    do { __asm volatile ("mov r6, %z0" : : "rM" (value)); } while (0)
#define NIOS2_WRITE_R7(value) \
    do { __asm volatile ("mov r7, %z0" : : "rM" (value)); } while (0)
#define NIOS2_WRITE_R8(value) \
    do { __asm volatile ("mov r8, %z0" : : "rM" (value)); } while (0)
#define NIOS2_WRITE_R9(value) \
    do { __asm volatile ("mov r9, %z0" : : "rM" (value)); } while (0)


static inline int
syscall(int num, ...) {
    va_list ap;
    va_start(ap, num);
    uint32_t a[MAX_ARGS];
    int i, ret;
    for (i = 0; i < MAX_ARGS; i ++) {
        a[i] = va_arg(ap, uint32_t);
    }
    va_end(ap);
    
    NIOS2_WRITE_R4(num);
    NIOS2_WRITE_R5(a[0]);
    NIOS2_WRITE_R6(a[1]);
    NIOS2_WRITE_R7(a[2]);
    NIOS2_WRITE_R8(a[3]);
    NIOS2_WRITE_R9(a[4]);

    asm volatile ("trap");
    
    NIOS2_READ_R2(ret);
    
    return ret;
}

int
sys_exit(int error_code) {
    return syscall(SYS_exit, error_code);
}

int
sys_fork(void) {
    return syscall(SYS_fork);
}

int
sys_wait(int pid, int *store) {
    return syscall(SYS_wait, pid, store);
}

int
sys_yield(void) {
    return syscall(SYS_yield);
}

int
sys_kill(int pid) {
    return syscall(SYS_kill, pid);
}

int
sys_getpid(void) {
    return syscall(SYS_getpid);
}

int
sys_putc(int c) {
    return syscall(SYS_putc, c);
}

int
sys_pgdir(void) {
    return syscall(SYS_pgdir);
}

